在看了网上类似于BFC的技术博客后,也是看了好几篇再加上看了官方文档后,才大概对BFC这个面试经常问的东西有了一点理解,所以就抱着尽量通俗易懂的方式给后面需要了解BFC特性同学讲解,尽量让你只需看这一篇就能有个大概的理解,这也是本次写这篇的文章的初衷。
前世
BFC是什么?为什么有这个东西?它有什么作用?为了回答这些问题,我们先来想一想这么一个场景:盘古开天地之际,一个页面上面只有几个div
,span
元素,这个时候没有块级元素和行内级元素的概念,更没有边框边距的概念,那请问这几个元素该怎么排列表现呢?
为了解决这个问题,女娲(w3c),先教给这几个元素一些生存的本领吧,不然饿死了咋办,于是它们学会了穿衣服(padding
),防护罩(margin
)等,这也就是盒模型的由来,当然,盒模型不是本次的重点,我们只需要知道盘古开天辟地之际div
,span
等元素都学会了盒模型这一本领。
本领都学会了,那不得派它们出去帮女娲(w3c)干活,但是大家学的本领都一样,而且每个地方的环境都是千差万变的,这可不行,于是女娲(w3c)便开始对不同类型的元素传授不同技能,时间久了,女娲(w3c)觉得这样子太耗精力,便成立了一个部门(视觉格式化模型),专门将这些学会本领的元素二次培训成更高级的元素,简称盒子,而它们唯一的身份区别就是display
属性,这些盒子在不同的地方任职(指盒子的布局),其权力(盒子的布局因素)受限于四大因素影响:
- 盒子尺寸和类型
- 定位方案(普通流定位、浮动定位或绝对定位)
- 文档树中元素之间的关系
- 外部因素(例如,视口大小,图像的固有尺寸等)
随着历史发展,这些盒子通过自身的修炼已经发展成不同的类型了,也衍生出了很多新的概念,具体如下:
概念 | 描述 |
块 | 文档流中的独立的区域,相互之间在垂直方向上按照顺序依次堆叠 |
包含块 | 包含其他盒子的块称为包含块 |
盒子 | CSS引擎根据文档中的内容所创建,主要用于文档元素的定位、布局和格式化等(多个元素可以合并成一个盒子,一个元素也可生成多个盒子,如匿名盒子) |
块级元素 | display 为block 、list-item 、table 时,该元素将成为块级元素(元素是否是块级元素仅是元素本身的属性,并不直接用于格式化上下文的创建或布局) |
块级盒子 | 由块级元素生成(一个块级元素至少会生成一个块级盒子,但也有可能生成多个,例如列表项元素) |
块容器盒子 | 块容器盒子侧重于当前盒子作为“容器”的这一角色,它不参与当前块的布局和定位,它所描述的仅仅是当前盒子与其后代之间的关系。换句话说,块容器盒子主要用于确定其子元素的定位、布局等 |
块盒子 | 块级盒子+块容器盒子简称块盒子(还可以分为匿名块盒子) |
行内级元素 | display 为 inline 、inline-block 、inline-table 的元素称为行内级元素(同块级元素类似,行内级元素仅是元素本身的属性,不直接用于格式化上下文的创建或布局) |
行内级盒子 | 由行内级元素生成 |
行内盒子 | 参与行内格式化上下文创建的行内级盒子称为行内盒子(也分匿名行内盒子) |
原子行内级盒子 | 不参与行内格式化上下文创建的行内级盒子称为原子行内级盒子 |
最后整理了一个导航图,方便大家快速记忆:
篇幅有限,如果想具体的了解这些盒子的介绍以及说明,请点击这里。
今生
what
通过上面的故事回忆并结合,我们再来讲讲块格式化上下文(Block Formatting Context,BFC),大体我们可以认为BFC是Web页面的可视化CSS渲染的一部分内容,如果再具体一点就是:
- 块盒子的布局过程发生的区域
- 浮动元素与其他元素交互的区域
块盒子在上面我们已经讲了,就是块级盒子+块容器盒子简称块盒子;而浮动元素这里主要指元素的 float
不是 none
的元素。
why
通过前世我们可以大致发现BFC主要是因为前端发展越来越快,页面布局日益复杂,为了应对这些需求从而应运而生,并且其拥有一些特殊的特性,我们从而可以利用这些特性去解决某一类问题,如清除浮动,防止margin重叠等问题。
how
在我们谈BFC有什么作用之前,我们得知道怎么触发BFC机制,这是先决条件,通过查阅文档并整理了表格如下:
条件太多,可能一时半会儿也记不住,可以添加为书签方便日后查找,现在我们来探讨一下BFC
都有哪些特性,通过查阅规范文档可以总结如下:
- 块级盒从一个包含块的顶部开始一个接一个地垂直排列
- 两个兄弟块级盒之间的垂直距离由
margin
属性决定,并且在同一个BFC
中的元素发生margin collapse
- 每个块级盒的左外边缘相邻包含块的左边缘(同理从左往右格式化,则与包含块的右边缘相邻)
- BFC具有‘密室’特性,密室里面的元素不会影响到密室外面的元素,反之亦然
- 计算BFC的大小时,考虑所有所包含的元素,包括浮动元素
文字总是给人苍白无力的感觉,还是让我们看看demo是怎么一一解释以上特性的。
示例一
根元素(这里指HTML)默认会创建一个BFC,我们可以看到块级盒是从上到下垂直排列,也就是我们的特性一(块级盒从一个包含块的顶部开始一个接一个地垂直排列),块级盒就是这里的h1
,p
和div
标签所渲染的盒子,而包含块就是我们这里的HTML
标签默认创建的BFC区域,最终的渲染结果就是从包含块的顶部一个接着一个的垂直排列,从而很好的解释了BFC得特性一。
示例二
由示例二我们可以看出,在同一个BFC中,块级盒垂直方向的距离由上下 margin
属性决定,并且会发生margin callapse
,其规则可以简记同大异和
。翻译过来就是如果两个元素margin
都为正值,则取两者之中较大的那一个为,如果两个元素margin
都为负值,则取两者之中绝对值较大的那一个,这就是相同符号的取较大的那一个,简记同大
;如果两个元素margin
为一正一负,则取两个margin
相加之和为最终的值,简记异和
,具体效果我们可以查看示例三。
示例三
通过示例三,我们也了解了margin collapse
规则,这也验证了BFC的特性二(两个兄弟块级盒之间的垂直距离由margin
属性决定,并且在同一个BFC
中的元素发生margin collapse
),下面我们来看看BFC的特性三**的例子。
示例四
通过打开浏览器的审查工具,将鼠标移到h1
标签的margin
属性上面,即可看到margin
属性所渲染的区域:
同理我们将鼠标移到div标签的padding属性上面,即可看到padding所渲染的区域:
通过结合两张图我们可以清晰看到每个块级盒的左外边缘(margin)相邻包含块的左边缘(padding),从而验证了BFC的特性三(每个块级盒的左外边缘相邻包含块的左边缘)。
示例五
默认情况下我们可以看到区域一
直接跑到了左浮动区域
底部,如果点击设置BFC
按钮,我们可以看到区域一
跑到了右上角,因为BFC
具有密室
特性,在密室
内的元素都不会跑到密室
外面从而造成溢出,但是只要我们点击取消BFC
,我们可以马上看到区域一一下就溢出了,这也很好的解释了BFC得特性四(BFC具有‘密室’特性,密室里面的元素不会影响到密室外面的元素)。
示例六
默认情况下父级标签触发了BFC
,左浮动区域
设置了float:left
,似乎一切都符合我们的认知预期,但是当我们点击取消BFC
按钮时,却发现左浮动区域
的背景色没了,打开审查工具查看发现父级元素好像真的并没有包裹左浮动区域
,左浮动区域
似乎‘溢出’了父级标签的容器,我们都知道浮动元素特性就是该元素从网页的正常流动(文档流)中移除,尽管仍然保持了部分的流动性,原来取消掉BFC
才是我们常见的情景,也就是浮动元素会造成高度坍塌
,解决这种问题常用解决方案有很多,比如利用伪元素清除浮动,在这里我们利用BFC
的特性5(计算BFC的大小时,考虑所有所包含的元素,包括浮动元素),我们只需要让父级元素触发BFC
即可,这里我们使用overflow
进行触发,具体效果我们可以点击设置BFC
按钮进行预览。
作用
在前面我们讲述了BFC得前世今生,对BFC的触发条件、特性都进行了一一介绍,BFC我们似乎是懂了不少,但是BFC具体有哪些实际作用我们还是需要学习的,正所谓学以致用,下面我们看看有哪些:
示例七
结尾
BFC的概念这里也是结合笔者自身理解以及查阅了一些文档总结而成,如文中有论述错误的地方,还望批评指正。
参考
[1]Understanding Block Formatting Contexts in CSS
[2]block-formatting
[3]格式化上下文
[4]视觉格式化模型